package logic;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.PriorityQueue;
import java.util.Scanner;

import resources.Configuration;

/**
 * represents the record table of the Game
 * the score is the number of moves the player made until he won
 */
public class RecordTable {

	private PriorityQueue<Record> records = new PriorityQueue<Record>();

	private static File recordTableFile;

	// numebr of recoreds which will be saved in the record table 
	public static final int numberOfRecords = 12;

	/**
	 * creating the record table file if not existed
	 * reading all the records from the file into the data structure
	 */
	public RecordTable(){
		new File(Configuration.homeDir).mkdirs();
		String filePath = Configuration.homeDir + File.separator + "records.data";
		RecordTable.recordTableFile = new File(filePath);
		readFromFile();
	}

	private void readFromFile(){
		this.records.clear();
		Scanner scanner = null;
		if(!RecordTable.recordTableFile.exists()){
			System.out.println("Record Table file is not found. A new one created.");
			try {
				RecordTable.recordTableFile.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
				System.err.println("Unable to create records table file.");
				return;
			}
		}
		try {
			scanner = new Scanner(new FileReader(RecordTable.recordTableFile));
		} catch (FileNotFoundException e) {
			System.err.println("Unable to open records table file.");
		}
		while(scanner.hasNextLine()){
			String[] data = scanner.nextLine().split(" ");
			this.records.add(new Record(data[0], Integer.valueOf(data[1])));
		}
		scanner.close();
	}

	/**
	 * adding the game result of the winner "player" to the record table iff
	 * the score of the player is higher then the minimum score in the current
	 * record table
	 */
	public void addToRecordTable(Player player){
		Record newRecord = new Record(player.getPlayerName(), player.getTotalNumOfMoves());
		if(this.records.size() >= RecordTable.numberOfRecords){
			Record lowest = this.records.peek();
			if(newRecord.compareTo(lowest) > 0){
				this.records.poll();
				this.records.add(newRecord);
			}
		} else {
			this.records.add(newRecord);
		}
		updateRecordFile();
	}

	/**
	 * updates the file in which the record table s stored
	 */
	private void updateRecordFile() {
		if(RecordTable.recordTableFile.exists()){
			RecordTable.recordTableFile.delete();
		}
		BufferedWriter bw = null; 
		try {
			RecordTable.recordTableFile.createNewFile();
			bw = new BufferedWriter(new FileWriter(RecordTable.recordTableFile));
		} catch (IOException e) {
			System.err.println("Unable to update the records table");
		}
		// update the record table
		for(Record record: this.records){
			try {
				bw.write(record.getPlayerName() + " " + record.getPlayerRecord() + "\n");
			} catch (IOException e) {
				System.err.println("Unable to update the records table");
			}
		}
		// releasing resources
		try {
			bw.close();
		} catch (IOException e) {
			System.err.println("An error may have occured while updating records");
		}
	}

	/**
	 * returns a string representation of the record table
	 */
	public String toString(){
		String recordTable = "";
		PriorityQueue<Record> temp = new PriorityQueue<Record>();
		for(Record record : this.records){
			temp.add(record);
		}
		while(temp.size()>0){
			recordTable = temp.poll() + recordTable;
		}
		if(recordTable.trim().equals("")){
			return "No records";
		} else {
			return recordTable;
		}
	}

	public boolean isHasRecord(Player player){
		for(Record record : this.records){
			if(record.getPlayerName().equals(player.getPlayerName()))
				return true;
		}
		return false;
	}
}

/**
 * represents a record in the record table
 */
class Record implements Comparable<Record> {

	//recordes counter
	private static int counter;

	// the name of the player who made the record
	private String playerName; 

	// the number of oves (score) the player made until winning
	private int numberOfMoves;

	//record id
	private int id;

	public Record(String playerName, int score){
		this.playerName = playerName;
		this.numberOfMoves = score;
		this.id = Record.counter++;
	}

	public Record(Player player, int score){
		this(player.getPlayerName(), score);
	}

	/**
	 * comparing two records:
	 * the record with the less move is higher ranked
	 */
	public int compareTo(Record object){
		Record record = (Record)object;
		if(record.numberOfMoves == this.numberOfMoves){
			return (this.id>object.id)?1:-1;
		} else if(record.numberOfMoves > this.numberOfMoves){
			return 1;
		} else {
			return -1;
		}
	}

	public int getPlayerRecord(){
		return this.numberOfMoves;
	}

	public String getPlayerName(){
		return this.playerName;
	}

	public String toString(){
		return this.playerName + ":\t" + this.numberOfMoves + "\n";
	}

	public boolean equals(Object object){
		Record record = (Record)object;
		return (this.numberOfMoves == record.numberOfMoves) && (this.playerName == record.playerName);
	}
}
